/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pigx.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.enums.AbnormalEnum;
import com.pig4cloud.pigx.common.customize.enums.CommonDictEnum;
import com.pig4cloud.pigx.common.customize.exception.DuckweedException;
import com.pig4cloud.pigx.common.customize.mysql.utils.MysqlUtil;
import com.pig4cloud.pigx.common.customize.security.utils.SecurityUtil;
import com.pig4cloud.pigx.common.customize.utils.id.IdWorker;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.strategy.api.feign.StrategyContractFeign;
import com.pig4cloud.pigx.user.constant.WalletConstant;
import com.pig4cloud.pigx.user.dto.AppTransferPageDTO;
import com.pig4cloud.pigx.user.dto.TransferDTO;
import com.pig4cloud.pigx.user.dto.UserTransferDTO;
import com.pig4cloud.pigx.user.entity.*;
import com.pig4cloud.pigx.user.enums.TransferEnums;
import com.pig4cloud.pigx.user.mapper.TransferDetailedMapper;
import com.pig4cloud.pigx.user.mapper.UserMapper;
import com.pig4cloud.pigx.user.service.*;
import com.pig4cloud.pigx.user.vo.LoginUserTransferVO;
import lombok.AllArgsConstructor;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 划转记录i
 *
 * @author pigx code generator
 * @date 2022-11-28 15:30:10
 */
@Service
@AllArgsConstructor
public class TransferDetailedServiceImpl extends ServiceImpl<TransferDetailedMapper, TransferDetailed> implements TransferDetailedService {

	private final MysqlUtil mysqlUtil;

	private final UserMapper userMapper;

	private final FuelAccountService fuelAccountService;

	private final CapitalAccountService capitalAccountService;

	private final IdWorker idWorker;

	private final AmqpTemplate rabbit;

	private final UserService userService;

	private final StrategyContractFeign strategyContractFeign;


	@Override
	public R<Page<LoginUserTransferVO>> getAppPage(AppTransferPageDTO dto) {
		try {
			PigxUser user = SecurityUtil.getLoginUser();
			if (user == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND);
			}
			Page<TransferDetailed> page = baseMapper.selectPage(new Page<TransferDetailed>() {{
				setCurrent(dto.getCurrent());
				setSize(dto.getSize());
			}}, new QueryWrapper<TransferDetailed>() {{
				if (dto.getType() != null) {
					if (dto.getType().equals(TransferEnums.Type.TO_FUEL.getValue())) {
						in("type",TransferEnums.Type.TO_FUEL.getValue(),TransferEnums.Type.REWARD_TO_FUEL.getValue());
					} else {
						eq("type", dto.getType());
					}
				}
				if (dto.getType() != null && dto.getType().equals(TransferEnums.Type.FUEL_TRANSACTION.getValue())) {
					eq("user_id", user.getId()).or().eq("to_user_id",user.getId());
				} else {
					eq("user_id", user.getId());
				}
				if (dto.getStartTime() != null) {
					ge("create_time", dto.getStartTime());
				}
				if (dto.getEndTime() != null) {
					le("create_time", dto.getEndTime());
				}
				select(
						"quantity",
						"to_user_id",
						"currency",
						"type",
						"contribution_value",
						"fuel_set_meal_id",
						"create_time",
						dto.getType().equals(TransferEnums.Type.TO_FUEL.getValue()) ?
								"(select name from fuel_set_meal where id = fuel_set_meal_id) 'fuelSetMeal'"
								: "user_id"
				);
				orderByDesc("create_time");
			}});
			Page<LoginUserTransferVO> voPage = new Page<>();
			BeanUtils.copyProperties(page,voPage);
			List<LoginUserTransferVO> voList = new ArrayList<>();
			for (TransferDetailed record : page.getRecords()) {
				LoginUserTransferVO vo = new LoginUserTransferVO();
				BeanUtils.copyProperties(record,vo);
				if (vo.getType().equals(TransferEnums.Type.FUEL_TRANSACTION.getValue())) {
					if (record.getUserId().equals(user.getId())) {
						vo.setType("转出");
					}
					if (record.getToUserId().equals(user.getId())) {
						vo.setType("转入");
					}
				} else {
					vo.setType(TransferEnums.Type.findName(vo.getType()));
				}
				vo.setQuantity(vo.getQuantity().setScale(6, RoundingMode.DOWN));
				voList.add(vo);
			}
			voPage.setRecords(voList);
			return R.ok(voPage);
		} catch (DuckweedException e) {
			throw e;
		} catch (Exception e) {
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED);
		}
	}

	/**
	 * 购买燃料包
	 */
	@Override
	public R<String> transfer(TransferDTO dto) {
		FuelSetMeal setMeal = new FuelSetMeal().selectById(dto.getFuelSetMealId());
		if (setMeal == null) {
			throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"燃料套餐不存在");
		}
		if (setMeal.getStatus().equals(CommonDictEnum.Status.DEPRECATED.getValue())) {
			throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"该套餐已停用");
		}
		if (dto.getType() == null || dto.getType().isEmpty() ||
				(!dto.getType().equals(TransferEnums.Type.TO_FUEL.getValue()) && !dto.getType().equals(TransferEnums.Type.REWARD_TO_FUEL.getValue()))
		) {
			throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"购买类型无效");
		}
		if (setMeal.getCapitalPrice() == null || setMeal.getFuelQuantity() == null) {
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED.getCode(),"燃料套餐异常,请联系管理人员");
		}
		// 自定义燃料套餐
		if (setMeal.getFuelQuantity().compareTo(BigDecimal.ZERO) <= 0) {
			if (dto.getQuantity() == null) {
				throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED.getCode(),"请输入购买数量");
			}
			if (dto.getQuantity().compareTo(setMeal.getCapitalPrice()) < 0) {
				throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED.getCode(),"购买数量不得小于" +
						setMeal.getCapitalPrice().stripTrailingZeros().toPlainString());
			}
			if (dto.getQuantity().scale() > 6) {
				throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED.getCode(),"购买数量精度不可超过6位");
			}
			setMeal.setCapitalPrice(dto.getQuantity());
			setMeal.setFuelQuantity(dto.getQuantity());
			setMeal.setContributionValue(dto.getQuantity().multiply(setMeal.getContributionValue()));
		}
		// 获取登录用户
		PigxUser user = SecurityUtil.getLoginUserNotNull();
		try {
			if (dto.getPassword() == null || dto.getPassword().isEmpty()) {
				throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED.getCode(),"请输入资金密码");
			}
			User select = new User().selectById(user.getId());
			if (select.getPassword() != null && !select.getPassword().equals(dto.getPassword())) {
				throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED.getCode(),"资金密码错误");
			}
			// 开启事务
			mysqlUtil.startLocalTx();
			// 查询资金账户
			CapitalAccount capitalAccount = capitalAccountService.getOne(new QueryWrapper<CapitalAccount>() {{
				eq("user_id", user.getId());
				eq("currency", dto.getCurrency());
				last("for update");
			}});
			if (capitalAccount == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),"用户不存在");
			}
			// 资金/奖励余额
			BigDecimal capitalBalance = dto.getType().equals(TransferEnums.Type.TO_FUEL.getValue()) ? capitalAccount.getBalance() : capitalAccount.getFrozen();
			// 查询燃料账户
			FuelAccount fuelAccount = fuelAccountService.getOne(new QueryWrapper<FuelAccount>() {{
				eq("user_id", user.getId());
				eq("currency", dto.getCurrency());
				last("for update");
			}});
			if (fuelAccount == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),"该用户未开通燃料账户");
			}
			// 燃料余额
			BigDecimal fuelBalance = fuelAccount.getBalance();
			// 资金转燃料
			if (setMeal.getCapitalPrice().compareTo(capitalBalance) > 0) {
				throw new DuckweedException(AbnormalEnum.MSG.BALANCE_NOT_SUFFICIENT.getCode(),"余额不足,购买失败");
			}
			// 划转
			if (dto.getType().equals(TransferEnums.Type.TO_FUEL.getValue())) {
				capitalAccount.setBalance(capitalBalance.subtract(setMeal.getCapitalPrice()));
			} else {
				capitalAccount.setFrozen(capitalBalance.subtract(setMeal.getCapitalPrice()));
			}
			fuelAccount.setBalance(fuelBalance.add(setMeal.getFuelQuantity()));
			// 增加充值数10倍的贡献值
			capitalAccount.setContributionValue(capitalAccount.getContributionValue().add(setMeal.getContributionValue()));
			capitalAccountService.updateById(capitalAccount);
			fuelAccountService.updateById(fuelAccount);
			long id = idWorker.nextId();
			baseMapper.insert(new TransferDetailed(){{
				setId(id);
				setUserId(user.getId());
				setFuelSetMealId(setMeal.getId());
				setQuantity(setMeal.getFuelQuantity());
				setCurrency(WalletConstant.USDT);
				setContributionValue(setMeal.getContributionValue());
				setType(dto.getType());
			}});
			// 更新伞充值业绩
			List<User> allParent = userService.getAllParent(user.getId());
			List<Long> longs = allParent.stream().map(User::getId).collect(Collectors.toList());
			userMapper.updateCommunityFuelRecharge(longs,setMeal.getFuelQuantity());
			// 提交事务
			mysqlUtil.commitLocalTx();
			// 开始制度分红
			userService.distribution(user.getId(),setMeal.getCapitalPrice(),id);
			// 如果划转至燃料账户后资产大于0 发送mq消息
//			if (fuelAccount.getBalance().compareTo(BigDecimal.ZERO) > 0 ) {
//				rabbit.convertAndSend(StrategyMqConstant.EXCHANGE_FANOUT_STRATEGY_CONTRACT_FUEL_RECHARGE,user.getId());
//			}
			return R.ok("充值燃油币成功");
		} catch (DuckweedException exception) {
			// 回滚事务
			mysqlUtil.rollbackLocalTx();
			throw exception;
		} catch (Exception exception) {
			// 回滚事务
			mysqlUtil.rollbackLocalTx();
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED);
		}
	}


	/**
	 * 用户转账
	 * @param dto dto
	 * @return r
	 */
	@Override
	public R<String> userTransfer(UserTransferDTO dto) {
		// 获取登录用户
		PigxUser user = SecurityUtil.getLoginUserNotNull();
		try {
			User select = new User().selectById(user.getId());
			if (select == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),"用户不存在");
			}
			if (dto.getPassword() == null || dto.getPassword().isEmpty()) {
				throw new DuckweedException(AbnormalEnum.MSG.UNSUPPORTED_OPERATION.getCode(),"请填写资金密码");
			}
			if (!select.getPassword().equals(dto.getPassword())) {
				throw new DuckweedException(AbnormalEnum.MSG.UNSUPPORTED_OPERATION.getCode(),"资金密码错误");
			}
			// 开启事务
			mysqlUtil.startLocalTx();
			// 如果有正在执行的策略,不能转账
			Long data = strategyContractFeign.userStartStrategyCount(user.getId(), SecurityConstants.FROM_IN).getData();
			if (data > 0) {
				throw new DuckweedException(AbnormalEnum.MSG.UNSUPPORTED_OPERATION.getCode(),"当前有正在执行的策略,不可向外转出燃油币");
			}

			// 查询燃料账户
			FuelAccount fuelAccount = fuelAccountService.getOne(new QueryWrapper<FuelAccount>() {{
				eq("user_id", user.getId());
				eq("currency", WalletConstant.USDT);
				last("for update");
			}});
			if (fuelAccount == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),"该用户未开通燃料账户");
			}
			// 燃料余额
			BigDecimal fuelBalance = fuelAccount.getBalance();
			if (fuelBalance == null || fuelBalance.compareTo(dto.getQuantity()) < 0) {
				throw new DuckweedException(AbnormalEnum.MSG.BALANCE_NOT_SUFFICIENT.getCode(),"燃料账户余额不足");
			}

			// 查询目标燃料账户
			FuelAccount toUserFuel = fuelAccountService.getOne(new QueryWrapper<FuelAccount>() {{
				eq("user_id", dto.getToUserId());
				eq("currency", WalletConstant.USDT);
				last("for update");
			}});
			if (toUserFuel == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),"转账目标用户未开通燃料账户");
			}
			// 修改双方余额 完成交易
			toUserFuel.setBalance(toUserFuel.getBalance().add(dto.getQuantity()));
			fuelAccount.setBalance(fuelAccount.getBalance().subtract(dto.getQuantity()));
			toUserFuel.updateById();
			fuelAccount.updateById();

			baseMapper.insert(new TransferDetailed(){{
				setId(idWorker.nextId());
				setUserId(user.getId());
				setToUserId(dto.getToUserId());
				setQuantity(dto.getQuantity());
				setCurrency(WalletConstant.USDT);
				setType(TransferEnums.Type.FUEL_TRANSACTION.getValue());
			}});

			mysqlUtil.commitLocalTx();
			return R.ok("转账成功");
		} catch (DuckweedException exception) {
			// 回滚事务
			mysqlUtil.rollbackLocalTx();
			throw exception;
		} catch (Exception exception) {
			// 回滚事务
			mysqlUtil.rollbackLocalTx();
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED);
		}
	}

}
